﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using WinScriptEngine.Parses.Interface;
using WinScriptEngine.Parses.Scope;

namespace WinScriptEngine.Parses.Impl
{
    #region ==== 异常类 ====
    class ControlParseException : UndefinedException
    {
        public ControlParseException(string message) : base(message) { }
        public ControlParseException(string message, Exception inner) : base(message, inner) { }
        protected ControlParseException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }
    class ControlRuntimeException : RuntimeException
    {
        public ControlRuntimeException(string message) : base(message) { }
        public ControlRuntimeException(string message, Exception inner) : base(message, inner) { }
        protected ControlRuntimeException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }
    #endregion
    /// <summary>
    /// 控制字符解析类
    /// </summary>
    class ControlParseImpl : SingletonObject<ControlParseImpl>, IParse
    {
        public string VTypeName => "Control";
        /// <summary>
        /// 内部控制信息存储类
        /// </summary>
        class CtrlInfo
        {
            /// <summary>
            /// 控制字符
            /// </summary>
            public Metadata value;
            /// <summary>
            /// 控制字符中控制了几个运算结果在执行环境中
            /// </summary>
            public int paramCount;
            /// <summary>
            /// 进入控制区域前的优先级
            /// </summary>
            public int oldLevel;
            /// <summary>
            /// 进入控制区域前还需要的参数数量
            /// </summary>
            public int oldNeedNumber;

            public CtrlInfo(Metadata value, int oldLevel, int oldNeedParam)
            {
                this.value = value;
                this.paramCount = 0;
                this.oldLevel = oldLevel;
                this.oldNeedNumber = oldNeedParam;
            }
        }

        /// <summary>
        /// 可以处理的控制字符
        /// </summary>
        private readonly string needCharList = ",(){}<>;";

        /// <summary>
        /// 控制字符栈
        /// </summary>
        private Stack<CtrlInfo> controlStack = new();

        public Metadata Parse(ref Metadata upper, IEnumerator<char> position)
        {
            Metadata result = new Metadata(MetadataType.Ctrl, position.Current.ToString());
            position.MoveNext();
            return result;
        }

        public bool TryParse(ref Metadata upper, char curChar)
        {
            return needCharList.IndexOf(curChar) >= 0;
        }

        // 需要拆分为函数
        public bool Invoke(InvokeEnvironment vCpu)
        {
            Metadata ctrlValue = vCpu.instructions[vCpu.eip];
            switch (ctrlValue.@object)
            {
                case ",":
                    { 
                        CtrlInfo ctrlInfo = controlStack.First();
                        ++ctrlInfo.paramCount;
                        vCpu.operLevel = int.MaxValue;
                        vCpu.ClearOperatorCache();
                        vCpu.needNumber = 1;
                    }
                    break;  
                case "(":
                    {
                        controlStack.Push(new(ctrlValue, vCpu.operLevel, vCpu.needNumber));
                        vCpu.operLevel = int.MaxValue;
                        vCpu.needNumber = 1;
                        vCpu.operators.Push(Operator.SplitOperator);
                    }
                    break;
                case ")":
                    {
                        CtrlInfo ctrlInfo = controlStack.Pop();
                        if (ctrlInfo.value.@object != "(")
                            throw new ControlRuntimeException("括号不匹配");

                        vCpu.operLevel = int.MaxValue;
                        vCpu.ClearOperatorCache();

                        if (vCpu.needNumber == 0)
                            ++ctrlInfo.paramCount;

                        List<Metadata> paramList = new();
                        for (int i = 0; i < ctrlInfo.paramCount; i++)
                            paramList.Insert(0, vCpu.results.Pop());

                        Metadata result;
                        if (vCpu.results.Count == 0 || 
                            vCpu.results.First().type != MetadataType.Symbol || 
                            ctrlInfo.oldNeedNumber > 0
                            )
                        {
                            --ctrlInfo.oldNeedNumber;
                            result = NullFunction(paramList);
                        }
                        else
                        {
                            Metadata value = vCpu.results.Pop() ;
                            result = vCpu.symbols.Invoke(vCpu, value.@object, paramList);
                        }
                        vCpu.results.Push(result);
                        if (vCpu.operators.Pop() != null)
                            throw new ControlRuntimeException("内部错误：分割运算符不正确");
                        vCpu.needNumber = 0;
                        vCpu.operLevel = ctrlInfo.oldLevel;
                        vCpu.needNumber = ctrlInfo.oldNeedNumber;
                    }
                    break;
                case "{":
                case "<":
                case ">":
                case "}":
                case ";":
                default:
                    throw new NotImplementedException();
            }
            return true;
        }
        Metadata NullFunction(List<Metadata> values)
            => values.Last();
    }
}
